package com.weidong.mybbs.config;

import org.apache.shiro.codec.Base64;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;

import java.util.LinkedHashMap;
import java.util.Map;

//@Configuration
public class ShiroConfig {


    // 登录地址
    @Value("${shiro.user.loginUrl}")
    private String loginUrl;
    //登录成功页面
    @Value("${shiro.user.successUrl}")
    private String successUrl;
    // 权限认证失败地址
    @Value("${shiro.user.unauthorizedUrl}")
    private String unauthorizedUrl;
    // 设置Cookie的域名
    @Value("${shiro.cookie.domain}")
    private String domain;
    // 设置cookie的有效访问路径
    @Value("${shiro.cookie.path}")
    private String path;
    // 设置HttpOnly属性
    @Value("${shiro.cookie.httpOnly}")
    private boolean httpOnly;
    // 设置Cookie的过期时间，秒为单位
    @Value("${shiro.cookie.maxAge}")
    private int maxAge;
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.timeout}")
    private int timeout;

    /**
     * 权限过滤拦截器
     * @return
     */
     @Bean
     public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){

         ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
         //Shiro的核心安全接口,这个属性是必须的
         factoryBean.setSecurityManager(securityManager);
         // 身份认证失败，则跳转到登录页面的配置
         factoryBean.setLoginUrl(loginUrl);
         //登录成功跳转页面
         factoryBean.setSuccessUrl(successUrl);
         // 权限认证失败，设置未授权提示跳转到指定页面
         factoryBean.setUnauthorizedUrl(unauthorizedUrl);


         //添加shiro内置过滤器
         /**
          * Shiro 内置过滤器，可以实现权限相关的拦截器
          *      常用的过滤器:
          *         anon:无需认证(登录)可以访问
          *         authc:必须认证才可以访问
          *         user:如果使用了rememnberMe的功能才可以直接访问
          *         perms:该资源必须得到资源权限才可以访问
          *         role：必须得到角色权限才可以访问
          */
         // Shiro连接约束配置，即过滤链的定义
         Map<String,String> filterMap = new LinkedHashMap<>();
         // 对静态资源设置匿名访问
         filterMap.put("/login","anon");
         filterMap.put("/static/*","anon");
         filterMap.put("/error/*","anon");
         //授权过滤器
         filterMap.put("/add","perms[user:add]");
         //设置记住我时，用户存在，直接访问首页
         filterMap.put("/index","user");
         filterMap.put("/unauth","anon");
         filterMap.put("/*","authc");
         //修改跳转的登录页面
         factoryBean.setFilterChainDefinitionMap(filterMap);
         return factoryBean;
     }

     /**
      * 安全管理器
      * @return
      */
    @Bean("securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        //关联自定义realm
        manager.setRealm(userRealm);
        //注入记住我管理器
        // 记住我
        manager.setRememberMeManager(rememberMeManager());
       // 自定义session管理 使用redis
        manager.setSessionManager(sessionManager());
        return manager;
    }

    /**
     * 自定义安全域，用户验证、权限等数据在此提供
     * @return
     */
    @Bean("userRealm")
    public UserRealm getRealm(){
        return new UserRealm();
    }

    /**
     * Session Manager
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }
    /**
     * RedisSessionDAO shiro sessionDao层的实现 通过redis
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }
    /**
     * 配置shiro redisManager
     * 使用的是shiro-redis开源插件
     * @return
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        redisManager.setPassword(password);
        redisManager.setExpire(1800);// 配置缓存过期时间
        redisManager.setTimeout(timeout);
        // redisManager.setPassword(password);
        return redisManager;
    }
    /**
     * cookie 属性设置
     */
    public SimpleCookie rememberMeCookie()
    {
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        cookie.setDomain(domain);
        cookie.setPath(path);
        cookie.setHttpOnly(httpOnly);
        //设置cookie生效时间60天，单位秒
        cookie.setMaxAge(maxAge * 24 * 60 * 60);
        return cookie;
    }
    /**
     * 记住我
     */
    public CookieRememberMeManager rememberMeManager()
    {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        cookieRememberMeManager.setCipherKey(Base64.decode("fCq+/xW488hMTCD+cmJ3aQ=="));
        return cookieRememberMeManager;
    }

}
